#pragma once
#include <stdio.h>
#include <iostream>
#include <string>
#include <mutex>
#include <vector>
#include <utility>
#include <unordered_map>
#include "connector/include/mysql.h"
#include "./log/log.hpp"
#include "MysqlPool.hpp"
#include "hiredis/hiredis.h"
const std::string client_table = "account"; // 账号
const std::string admin_table = "account";
const std::string user_table = "user"; // 业主信息
const std::string repair_table = "repair";
const std::string pay_table = "pay";
const std::string medical_table = "medical";

#define NOEXIST 0  // 账号不存在
#define EXIST 1    // 账号存在
#define SQLERROR 2 // 执行sql语句出错
#define ADD_Y 3    // 注册账号成功

typedef std::unordered_map<std::string, std::string> Info;
typedef std::vector<std::vector<std::pair<std::string, std::string>>> Data;
// 多态，client和admin分别调用各自的方法
class Object
{
public:
   virtual int query(MYSQL *mysql, Info &result, MysqlPool *){}; // result 输出型参数
   virtual int insert(MYSQL *mysql, MysqlPool *){};
};
class user : public Object
{
private:
   std::string name;
   std::string addr;
   std::string tele;
   std::string login;
};
class admin : public Object
{
public:
   admin(const std::string &name, const std::string &password, const std::string &login = "2023-04-17")
       : login_(login), name_(name), password_(password)
   {
   }
   // 查询是否存在该用户,同时获得信息
   int query(MYSQL *mysql, Info &result, MysqlPool *pool)
   {
      int status;
      const std::string sql = "select *from " + client_table + " where name=" + "'" + name_ + "'";
      if (mysql_query(mysql, sql.c_str()) == 0)
      {
         MYSQL_RES *res = mysql_store_result(mysql);
         MYSQL_RES res_bak = *res; // 拷贝结果
         // 判断查询结果
         if (mysql_fetch_row(res) == nullptr)
         {
            status = NOEXIST;
         }
         else
         {
            // 获得列表字段名称
            MYSQL_FIELD *field;
            std::vector<std::string> column_name;
            while (field = mysql_fetch_field(res))
            {
               column_name.push_back(std::string(field->name));
            }
            // 每一行
            MYSQL_ROW row;
            while (row = mysql_fetch_row(&res_bak))
            {
               for (int i = 0; i < column_name.size(); i++)
               {
                  result.emplace(column_name[i], row[i]);
               }
            }
            status = EXIST;
         }
         mysql_free_result(res);
      }
      else
      {
         LOGERR(sql + " error");
         status = SQLERROR;
      }
      pool->ReleaseCon(mysql);
      return status;
   }

   int insert(MYSQL *mysql, MysqlPool *pool)
   {
      int status;
      const std::string sql = "insert into " + admin_table + "(login,name,password) values(" + "'" + login_ + "'" + "," + "'" + name_ + "'" + "," + "'" + password_ + "'" + ")";
      if (mysql_query(mysql, sql.c_str()) == 0)
      {
         LOG(NOTICE, "添加账号 " + name_ + " 成功");
         status = ADD_Y;
      }
      else
      {
         LOGERR(sql + " error");
         status = SQLERROR;
      }
      pool->ReleaseCon(mysql);
      return status;
   }

private:
   std::string login_;    // login-time
   std::string name_;     // username
   std::string password_; // password
};

class client : public Object
{
public:
   client(const std::string &rank, const std::string &name, const std::string &password)
       : rank_(rank), name_(name), password_(password)
   {
   }
   // 查询是否存该管理员
   int query(MYSQL *mysql, Info &result)
   {
      const std::string sql = "select *from " + admin_table + " where name=" + "'" + name_ + "'";
      if (mysql_query(mysql, sql.c_str()) == 0)
      {
         MYSQL_RES *res = mysql_store_result(mysql);
         MYSQL_RES res_bak = *res; // 拷贝结果
         // 判断查询结果
         if (mysql_fetch_row(res) == nullptr)
         {
            return NOEXIST;
         }
         else
         {
            // 获得列表字段名称
            MYSQL_FIELD *field;
            std::vector<std::string> column_name;
            while (field = mysql_fetch_field(res))
            {
               column_name.push_back(std::string(field->name));
            }
            // 每一行
            MYSQL_ROW row;
            while (row = mysql_fetch_row(&res_bak))
            {
               for (int i = 0; i < column_name.size(); i++)
               {
                  result.emplace(column_name[i], row[i]);
               }
            }
         }
      }
      else
      {
         LOGERR(sql + " error");
         return SQLERROR;
      }
      return EXIST;
   }
   int insert(MYSQL *mysql)
   {
      const std::string sql = "insert into " + admin_table + "(`rank`,name,password) values(" + "'" + rank_ + "'" + "," + "'" + name_ + "'" + "," + "'" + password_ + "'" + ")";

      if (mysql_query(mysql, sql.c_str()) == 0)
      {
      }
      else
      {
         LOGERR(sql + " error");
         return SQLERROR;
      }
      return ADD_Y;
   }

private:
   std::string rank_;
   std::string name_;
   std::string password_;
};

class Manager
{
private:
   static Manager *instance;    // Manager对象单例
   static MysqlPool *mysqlPool; // MYSQL连接池单例
   static std::mutex mtx_;

private:
   Manager(){};
   Manager(const Manager &) = delete;
   Manager operator=(const Manager &) = delete;

public:
   // 创建manager单例
   static Manager *GetInstance()
   {
      if (instance == nullptr)
      {
         mtx_.lock();
         if (instance == nullptr)
         {
            instance = new Manager();
         }
         mtx_.unlock();
      }
      return instance;
   }
   // 初始化mysql服务
   bool init()
   {
      mysqlPool = MysqlPool::GetInstance(6, "root", "Bit104-7274", "web");
   }

   // 查询用户注册信息
   int Query(Object *obj, Info &result)
   {
      MYSQL *con = mysqlPool->GetConnection();
      return obj->query(con, result, mysqlPool);
   }

   // 注册账号
   int AddAccount(Object *obj)
   {
      MYSQL *con = mysqlPool->GetConnection();
      Info result;
      return obj->insert(con, mysqlPool);
   }

   int GetUserData(Data &output)
   {
      int status;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      mysql_options(con, MYSQL_SET_CHARSET_NAME, "utf8mb4");
      const std::string sql = "select *from " + user_table ;
      if (mysql_query(con,sql.c_str()) == 0)
      {
         MYSQL_RES *res = mysql_store_result(con);
         MYSQL_RES res_bak = *res; //拷贝结果
         //判断查询结果
         if( mysql_fetch_row(res)== nullptr)
         {
            status = NOEXIST;
         }
         else
         {
            //获得列表字段名称
            MYSQL_FIELD * field;
            std::vector<std::string> Column_name;
            while (field = mysql_fetch_field(res))
            {
               Column_name.push_back(std::string(field->name));
            }
            //每一行
            MYSQL_ROW row;
            while( row = mysql_fetch_row(&res_bak))
            {
               std::vector<std::pair<std::string,std::string>> row_data;
               for(int i=0;i<Column_name.size();i++)
               {
                  row_data.push_back (make_pair(Column_name[i],row[i]) );
               }
               output.push_back(std::move(row_data));
            }
            status = EXIST;
         }
         mysql_free_result(res);
      }
      else
      {
         LOGERR(sql+" error");
         status = SQLERROR;
      }
      mysqlPool->ReleaseCon(con);
      return status;
   }

   bool DelUserData(const std::string &addr)
   {
      bool ret;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      mysql_options(con, MYSQL_SET_CHARSET_NAME, "utf8mb4");
      const std::string sql = "delete from " + user_table + " where addr = " + "'" + addr + "'";
      if (mysql_query(con, sql.c_str()) == 0)
      {
         ret = true;
      }
      else
      {
         LOGERR(sql + " error");
         ret = false;
      }
      mysqlPool->ReleaseCon(con);
      return ret;
   }

   bool AddUserData(std::vector<std::string> info)
   {
      bool ret;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      mysql_options(con, MYSQL_SET_CHARSET_NAME, "utf8mb4");
      const std::string sql = "insert into " + user_table +
                              " values(" + "'" + info[0] + "'" + "," + "'" + info[1] + "'" + "," + "'" + info[2] + "'" + "," + "'" + info[3] + "'" + ")";
      if (mysql_query(con, sql.c_str()) == 0)
      {
         ret = true;
      }
      else
      {
         LOGERR(sql + " error");
         ret = false;
      }
      mysqlPool->ReleaseCon(con);
      return ret;
   }

   int GetPayList(Data &output)
   {
      int status;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      mysql_options(con, MYSQL_SET_CHARSET_NAME, "utf8mb4");
      const std::string sql = "select *from " + pay_table;
      if (mysql_query(con, sql.c_str()) == 0)
      {
         MYSQL_RES *res = mysql_store_result(con);
         MYSQL_RES res_bak = *res; // 拷贝结果
         // 判断查询结果
         if (mysql_fetch_row(res) == nullptr)
         {
            status = NOEXIST;
         }
         else
         {
            // 获得列表字段名称
            MYSQL_FIELD *field;
            std::vector<std::string> Column_name;
            while (field = mysql_fetch_field(res))
            {
               Column_name.push_back(std::string(field->name));
            }
            // 每一行
            MYSQL_ROW row;
            while (row = mysql_fetch_row(&res_bak))
            {
               std::vector<std::pair<std::string, std::string>> row_data;
               for (int i = 0; i < Column_name.size(); i++)
               {
                  row_data.push_back(make_pair(Column_name[i], row[i]));
               }
               output.push_back(std::move(row_data));
            }
            status = EXIST;
         }
         mysql_free_result(res);
      }
      else
      {
         LOGERR(sql + " error");
         status = SQLERROR;
      }
      mysqlPool->ReleaseCon(con);
      return status;
   }

   bool AddPayData(std::vector<std::string> info)
   {
      bool ret;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      mysql_options(con, MYSQL_SET_CHARSET_NAME, "utf8mb4");
      const std::string sql = "insert into " + pay_table +
                              " values(" + "'" + info[0] + "'" + "," + "'" + info[1] + "'" + "," + "'" + info[2] + "'" + "," + "'" + info[3] + "'" + "," + "'" + info[4] + "'" + ")";
      if (mysql_query(con, sql.c_str()) == 0)
      {
         ret = true;
      }
      else
      {
         LOGERR(sql + " error");
         ret = false;
      }
      mysqlPool->ReleaseCon(con);
      return ret;
   }

   bool DelPayData(const std::string &id)
   {
      bool ret;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      const std::string sql = "delete from " + pay_table + " where id = " + "'" + id + "'";
      if (mysql_query(con, sql.c_str()) == 0)
      {
         ret = true;
      }
      else
      {
         LOGERR(sql + " error");
         ret = false;
      }
      mysqlPool->ReleaseCon(con);
      return ret;
   }

   int GetRepairList(Data &output)
   {
      int status;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      mysql_options(con, MYSQL_SET_CHARSET_NAME, "utf8mb4");
      const std::string sql = "select *from " + repair_table;
      if (mysql_query(con, sql.c_str()) == 0)
      {
         MYSQL_RES *res = mysql_store_result(con);
         MYSQL_RES res_bak = *res; // 拷贝结果
         // 判断查询结果
         if (mysql_fetch_row(res) == nullptr)
         {
            status = NOEXIST;
         }
         else
         {
            // 获得列表字段名称
            MYSQL_FIELD *field;
            std::vector<std::string> Column_name;
            while (field = mysql_fetch_field(res))
            {
               Column_name.push_back(std::string(field->name));
            }
            // 每一行
            MYSQL_ROW row;
            while (row = mysql_fetch_row(&res_bak))
            {
               std::vector<std::pair<std::string, std::string>> row_data;
               for (int i = 0; i < Column_name.size(); i++)
               {
                  row_data.push_back(make_pair(Column_name[i], row[i]));
               }
               output.push_back(std::move(row_data));
            }
            status = EXIST;
         }
         mysql_free_result(res);
      }
      else
      {
         LOGERR(sql + " error");
         status = SQLERROR;
      }
      mysqlPool->ReleaseCon(con);
      return status;
   }

   bool DelRepairData(const std::string &id)
   {
      bool ret;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      const std::string sql = "delete from " + repair_table + " where id = " + "'" + id + "'";
      if (mysql_query(con, sql.c_str()) == 0)
      {
         ret = true;
      }
      else
      {
         LOGERR(sql + " error");
         ret = false;
      }
      mysqlPool->ReleaseCon(con);
      return ret;
   }

   bool AddRepairData(std::vector<std::string> info)
   {
      bool ret;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      mysql_options(con, MYSQL_SET_CHARSET_NAME, "utf8mb4");
      const std::string sql = "insert into " + repair_table +
                              " values(" + "'" + info[0] + "'" + "," + "'" + info[1] + "'" + "," + "'" + info[2] + "'" + "," + "'" + info[3] + "'" + "," + "'" + info[4] + "'" + ")";
      if (mysql_query(con, sql.c_str()) == 0)
      {
         ret = true;
      }
      else
      {
         LOGERR(sql + " error");
         ret = false;
      }
      mysqlPool->ReleaseCon(con);
      return ret;
   }

   int GetMedicalList(Data &output)
   {
      int status;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      mysql_options(con, MYSQL_SET_CHARSET_NAME, "utf8mb4");
      const std::string sql = "select *from " + medical_table;
      if (mysql_query(con, sql.c_str()) == 0)
      {
         MYSQL_RES *res = mysql_store_result(con);
         MYSQL_RES res_bak = *res; // 拷贝结果
         // 判断查询结果
         if (mysql_fetch_row(res) == nullptr)
         {
            status = NOEXIST;
         }
         else
         {
            // 获得列表字段名称
            MYSQL_FIELD *field;
            std::vector<std::string> Column_name;
            while (field = mysql_fetch_field(res))
            {
               Column_name.push_back(std::string(field->name));
            }
            // 每一行
            MYSQL_ROW row;
            while (row = mysql_fetch_row(&res_bak))
            {
               std::vector<std::pair<std::string, std::string>> row_data;
               for (int i = 0; i < Column_name.size(); i++)
               {
                  row_data.push_back(make_pair(Column_name[i], row[i]));
               }
               output.push_back(std::move(row_data));
            }
            status = EXIST;
         }
         mysql_free_result(res);
      }
      else
      {
         LOGERR(sql + " error");
         status = SQLERROR;
      }
      mysqlPool->ReleaseCon(con);
      return status;
   }

   bool DelMedicalData(const std::string &ident)
   {
      bool ret;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      const std::string sql = "delete from " + medical_table + " where ident = " + "'" + ident + "'";
      if (mysql_query(con, sql.c_str()) == 0)
      {
         ret = true;
      }
      else
      {
         LOGERR(sql + " error");
         ret = false;
      }
      mysqlPool->ReleaseCon(con);
      return ret;
   }

   bool AddMedicalData(std::vector<std::string> info)
   {
      bool ret;
      MYSQL * con = nullptr;
      while(con == nullptr)
      {
         con = mysqlPool->GetConnection();
      }
      mysql_options(con, MYSQL_SET_CHARSET_NAME, "utf8mb4");
      const std::string sql = "insert into " + medical_table +
                              " values(" + "'" + info[0] + "'" + "," + "'" + info[1] + "'" + "," + "'" + info[2] + "'" + "," + "'" + info[3] + "'" + "," + "'" + info[4] + "'" + "," + "'" + info[5] + "'" + "," + "'" + info[6] + "'" + ")";
      if (mysql_query(con, sql.c_str()) == 0)
      {
         ret = true;
      }
      else
      {
         LOGERR(sql + " error");
         ret = false;
      }
      mysqlPool->ReleaseCon(con);
      return ret;
   }
   ~Manager() {}
};
Manager *Manager::instance = nullptr;
MysqlPool *Manager::mysqlPool = nullptr;
std::mutex Manager::mtx_;